#ifndef WARP_H_
#define WARP_H_

#include "Color.h"

class Warp {
  public:
    // Describes the different scale modes.
    enum ScaleMode {
      AT_LEAST_UNITY,
      AT_MOST_UNITY,
      CUSTOM_SIZE,
    };
    // Describes the different crop modes.
    enum CropMode {
      CROP,
      FIT_ALL,
    };

    // Initialise with default settings.
    explicit Warp();
    // Default destructor would suffice, but virtual destructor desired!
    virtual ~Warp() {}
    // Use default copy constructor and assignment operator.

    // Scale controlled by pixel zoom: the least pixel magnification is 1x.
    virtual inline void setScaleAtLeastUnity();
    // Scale controlled by pixel zoom: the greatest pixel magnification is 1x.
    virtual inline void setScaleAtMostUnity();
    // Scale controlled by custom size.
    virtual inline void setScaleToSize(int width, int height);
    // Crop output circle so that no out-of-bounds pixels exist.
    virtual inline void setCrop();
    // Don't crop output circle. Extrapolate pixel colors when needed.
    virtual inline void setFitAllAndExtend();
    // Don't crop output circle. Fill unknown pixels with specified color.
    virtual inline void setFitAllAndFill(const Color& fill);

    // Set scale mode manually.
    virtual inline void setScaleMode(ScaleMode scale_mode);
    // Set crop mode manually.
    virtual inline void setCropMode(CropMode crop_mode);
    // Set whether to extend the colors at the outer radius when not cropped.
    virtual inline void setExtend(bool extend);
    // Set custom size manually.
    virtual inline void setCustomSize(int width, int height);
    // Set custom width manually.
    virtual inline void setCustomWidth(int width);
    // Set custom height manually.
    virtual inline void setCustomHeight(int height);
    // Set background fill manually.
    virtual inline void setFill(const Color& fill);

    // Accessors for scale/crop settings.
    inline ScaleMode scaleMode() const;
    inline CropMode cropMode() const;
    inline bool extend() const;
    inline int customWidth() const;
    inline int customHeight() const;
    inline Color fill() const;

    // Accessors and modifiers for other warp options.
    inline bool invertX() const;
    inline bool invertY() const;
    inline bool perspectify() const;
    virtual inline void setInvertX(bool invert_x);
    virtual inline void setInvertY(bool invert_y);
    virtual inline void setPerspectify(bool perspectify);

  private:
    // Scale and crop modes. Must be compatible at all times!
    ScaleMode scale_mode_;
    CropMode crop_mode_;
    bool extend_;
    // Specify a custom size when needed.
    int custom_width_;
    int custom_height_;
    // Specify a background fill color to use when needed.
    Color fill_;
    // Flip the output warp around either axis?
    bool invert_x_;
    bool invert_y_;
    // Apply exponential warp to correct aspect ratio?
    bool perspectify_;

    static const ScaleMode DEFAULT_SCALE_MODE_ = AT_LEAST_UNITY;
    static const CropMode DEFAULT_CROP_MODE_ = CROP;
    static const bool DEFAULT_EXTEND_ = false;
    static const int DEFAULT_WIDTH_ = 1024;
    static const int DEFAULT_HEIGHT_ = 768;
    static const Color DEFAULT_FILL_;
    static const bool DEFAULT_INVERT_X_ = false;
    static const bool DEFAULT_INVERT_Y_ = false;
    static const bool DEFAULT_PERSPECTIFY_ = true;
};

// Scale controlled by pixel zoom: the least pixel magnification is 1x.
void Warp::setScaleAtLeastUnity() {
  scale_mode_ = Warp::AT_LEAST_UNITY;
}

// Scale controlled by pixel zoom: the greatest pixel magnification is 1x.
void Warp::setScaleAtMostUnity() {
  scale_mode_ = Warp::AT_MOST_UNITY;
}

// Scale controlled by custom size.
void Warp::setScaleToSize(int width, int height) {
  scale_mode_ = Warp::CUSTOM_SIZE;
  custom_width_ = width;
  custom_height_ = height;
}

// Crop output circle so that no out-of-bounds pixels exist.
void Warp::setCrop() {
  crop_mode_ = CROP;
}

// Don't crop output circle. Extrapolate pixel colors when needed.
void Warp::setFitAllAndExtend() {
  crop_mode_ = FIT_ALL;
  extend_ = true;
}

// Don't crop output circle. Fill unknown pixels with specified color.
void Warp::setFitAllAndFill(const Color& fill) {
  crop_mode_ = FIT_ALL;
  extend_ = false;
  fill_ = fill;
}

// Set scale mode manually.
void Warp::setScaleMode(ScaleMode scale_mode) {
  scale_mode_ = scale_mode;
}

// Set crop mode manually.
void Warp::setCropMode(CropMode crop_mode) {
  crop_mode_ = crop_mode;
}

// Set whether to extend the colors at the outer radius when not cropped.
void Warp::setExtend(bool extend) {
  extend_ = extend;
}

// Set custom size manually.
void Warp::setCustomSize(int width, int height) {
  custom_width_ = width;
  custom_height_ = height;
}

// Set custom width manually.
void Warp::setCustomWidth(int width) {
  custom_width_ = width;
}

// Set custom height manually.
void Warp::setCustomHeight(int height) {
  custom_height_ = height;
}

// Set background fill manually.
void Warp::setFill(const Color& fill) {
  fill_ = fill;
}

// Returns the scale mode.
Warp::ScaleMode Warp::scaleMode() const {
  return scale_mode_;
}

// Returns the crop mode.
Warp::CropMode Warp::cropMode() const {
  return crop_mode_;
}

// Returns true if image color are extended when required rather than filled.
bool Warp::extend() const {
  return extend_;
}

// Returns the custom width setting.
int Warp::customWidth() const {
  return custom_width_;
}

// Returns the custom height setting.
int Warp::customHeight() const {
  return custom_height_;
}

// Returns a copy of the custom fill color.
Color Warp::fill() const {
  return fill_;
}

// Returns true if X invert is enabled.
bool Warp::invertX() const {
  return invert_x_;
}

// Returns true if Y invert is enabled.
bool Warp::invertY() const {
  return invert_y_;
}

// Returns true if exponential correction mapping is enabled.
bool Warp::perspectify() const {
  return perspectify_;
}

// Sets whether X invert is enabled.
void Warp::setInvertX(bool invert_x) {
  invert_x_ = invert_x;
}

// Sets whether Y invert is enabled.
void Warp::setInvertY(bool invert_y) {
  invert_y_ = invert_y;
}

// Sets whether exponential correction mapping is enabled.
void Warp::setPerspectify(bool perspectify) {
  perspectify_ = perspectify;
}

#endif
